/* vim:set noet ts=4: */
/** 
 * scim-python
 * 
 * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 *
 * $Id: $
 */
#include <Python.h>
#include "structmember.h"
#include "scim-python-config.h"

using namespace std;

struct PyConfig{
	PyObject_HEAD
	/* Type-specific fields go here. */
	ConfigPointer config;
};

const ConfigPointer &
PyConfig_from_pyobject (PyObject *object)
{
	PyConfig *config = (PyConfig *)object;
	return config->config;
}


PyObject *
PyConfig_write (PyConfig *self, PyObject *args)
{
	char *key;
	PyObject *value;
	PyObject *result = Py_False;
	
	ConfigPointer &config = self->config;

	if (!PyArg_ParseTuple(args, "sO:write", &key, &value))
			return NULL;
	
	if (PyString_Check (value)) {
		if (config->write (String (key), String (PyString_AsString (value))))
			result = Py_True;
	}
	else if (PyBool_Check (value)) {
		if (config->write (String (key), value == Py_True))
			result = Py_True;		
	}
	else if (PyInt_Check (value)) {
		if (config->write (String (key), (int) PyInt_AsLong (value)))
			result = Py_True;		
	}
	else if (PyFloat_Check (value)) {
		if (config->write (String (key), PyFloat_AsDouble (value)))
			result = Py_True;		
	}
	else {
		PyErr_SetString(PyExc_TypeError,
			"The value must be string, int, float or bool");
		return NULL;
	}

	Py_INCREF (result);
	return result;	
}

PyObject *
PyConfig_read (PyConfig *self, PyObject *args)
{
	char *key;
	PyObject *value;
	PyObject *result = Py_None;
	
	ConfigPointer &config = self->config;

	if (!PyArg_ParseTuple(args, "sO:read", &key, &value))
			return NULL;

	if (PyString_Check (value)) {
		String retval (config->read (String (key), String (PyString_AsString (value))));
		result = PyString_FromString (retval.c_str ());
	}
	else if (PyBool_Check (value)) {
		bool retval = config->read (String (key), value == Py_True);
		result = retval ? Py_True: Py_False;
		Py_INCREF (result);
	}
	else if (PyInt_Check (value)) {
		int retval = config->read (String (key), (int) PyInt_AsLong (value));
		result = PyInt_FromLong ((long)retval);
	}
	else if (PyFloat_Check (value)) {
		double retval = config->read (String (key), PyFloat_AsDouble (value));
		result = PyFloat_FromDouble (retval);
	}
	else {
		PyErr_SetString(PyExc_TypeError,
			"The value must be string, int, float or bool");
		return NULL;
	}

	return result;	
}


static int
PyConfig_init(PyConfig *self, PyObject *args, PyObject *kwds)
{
	new (&self->config) ConfigPointer (NULL);
	return 0;
}

static PyObject *
PyConfig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	PyConfig *self;

	self = (PyConfig *)type->tp_alloc(type, 0);
	PyConfig_init (self, args, kwds);
	return (PyObject *)self;
}


static int 
PyConfig_clear(PyConfig *self)
{
	self->config = NULL;
	return 0;
}

static void
PyConfig_dealloc(PyConfig* self)
{
	PyConfig_clear(self);
	PyObject_Del((PyObject*)self);
}


static PyMethodDef PyConfig_methods[] = {
	{ "write", (PyCFunction)PyConfig_write, METH_VARARGS,
	 "write a value related to a key"
	},
	{ "read", (PyCFunction)PyConfig_read, METH_VARARGS,
	 "read a value related to a key, you must give a default value"
	},
	{NULL}  /* Sentinel */
};

static PyMemberDef PyConfig_members[] = {
	{NULL}  /* Sentinel */
};


static PyTypeObject PyConfigType = {
	PyObject_HEAD_INIT(NULL)
	0,						 				/*ob_size*/
	"scim.Config", 							/*tp_name*/
	sizeof(PyConfig), 						/*tp_basicsize*/
	0,						 				/*tp_itemsize*/
	(destructor)PyConfig_dealloc,		   /*tp_dealloc*/
	0,			  						/*tp_print*/
	0,						 				/*tp_getattr*/
	0,										/*tp_setattr*/
	0,										/*tp_compare*/
	0,			  						/*tp_repr*/
	0,										/*tp_as_number*/
	0,			  						/*tp_as_sequence*/
	0,										/*tp_as_mapping*/
	0,			  						/*tp_hash */
	0,										/*tp_call*/
	0, //(reprfunc)PyConfig_str,   							/*tp_str*/
	0,					   				/*tp_getattro*/
	0,										/*tp_setattro*/
	0,					 					/*tp_as_buffer*/
	Py_TPFLAGS_DEFAULT,						/*tp_flags*/
	"Config objects",		 				/* tp_doc */
	0,					   					/* tp_traverse */
	0,										/* tp_clear */
	0,					   /* tp_richcompare */
	0,					   /* tp_weaklistoffset */
	0,					   /* tp_iter */
	0,					   /* tp_iternext */
	PyConfig_methods,			 /* tp_methods */
	PyConfig_members,			 /* tp_members */
	0,						 /* tp_getset */
	0,						 /* tp_base */
	0,						 /* tp_dict */
	0,						 /* tp_descr_get */
	0,						 /* tp_descr_set */
	0,						 /* tp_dictoffset */
	0,						  /* tp_init */
	0,						 /* tp_alloc */
	0,				/* tp_new */	
};

PyObject *PyConfig_New (const ConfigPointer &config)
{
	PyConfig *obj = PyObject_New (PyConfig, &PyConfigType);
	
	new (&obj->config) ConfigPointer (config);
	
	return (PyObject *)obj;
}


void init_config (PyObject *module)
{
	PyObject *dict;

	if (PyType_Ready(&PyConfigType) < 0)
		return;
}

